<?php
/**
 * Created by PhpStorm.
 * User: guokunsheng
 * Date: 2018/6/20
 * Time: 10:56
 */

namespace app\common\lib;

use app\common\lib\apns\ApnsPush;
use app\common\model\User;
use app\common\model\UserPush;
use JPush\Client as JPush;
use think\Config;
use think\Db;
use think\Env;
use think\Log;
use XznsTools\cache\CacheManage;
use XznsTools\push\Huawei;
use XznsTools\push\Oppo;
use XznsTools\push\Vivo;
use XznsTools\push\Xiaomi;
use GuzzleHttp\Exception\GuzzleException;

class Push
{
    protected $pushTokenCacheModel = 'push_token'; //huawei=>5 xiaomi=>4 vivo=>3 oppo=>2 极光=> 1
    protected $app_key = '';
    protected $app_secret = '';
    protected $config = [];

    protected $cacheId = [
        'huawei' => 5,
        'xiaomi' => 4,
        'vivo' => 3,
        'oppo' => 2,
        'jpush' => 1,
    ];

    public function __construct()
    {
        // \think\Log::write('进入个推构造方法：','log',true);
        //  极光推送的配置

        $this->app_key = config('jpush.app_key');
        $this->app_secret = config('jpush.master_secret');

        // $this->config = config('push');
        $this->config = Config::Load(APP_PATH . 'extra/push.php', 'push', 'zhunle');;
    }

    /**
     * 向用户推送信息
     * @param $uid
     * @param $alert
     * @param $data
     * @param string $title
     * @return array|mixed
     */
    public function pushUserMsg($uid, $alert, $data, $title = '准了')
    {
        // 获取用户设备ID
        $userRegidData = (new UserPush())->where('uid', $uid)->field('device_token,push_type,regid,character_status')->find();
        if (!$userRegidData)
        {
            $userRegid = (new User())->where('id', $uid)->value('regid');
            $pushType = 1;
        } else
        {
            $userRegid = $userRegidData['regid'];
            $pushType = $userRegidData['push_type'];
            if ($userRegidData['character_status'] == 2)
            {   // 关闭个性化推送 取消个推
                return ['success' => true];
            }
        }

        if ($userRegid)
        {
            $extras = $this->getExtraData($data);
            $pushRecordData = [
                'uid' => $uid,
                'content' => $alert,
                'target' => $extras['target'] ?? '',
                'link' => $extras['action'] ?? '',
                'title' => $title,
                'admin_name' => 'api',
                'admin_id' => 0,
                'create_time' => time(),
            ];
            $mid = Db::table('wechat_backup_07_18_14_43_00.app_push_record')->insertGetId($pushRecordData);
            $extras['push_id'] = $mid;
            $extras['push_type'] = '个推';
            $extras['push_content'] = $alert;

            $pushData = [
                'plantform' => $pushType == 1 ? 1 : 3, // 1 => all  2 => IOS 3 => android
                'pushType' => $pushType,
                'regid' => [$userRegid],
                'title' => $title, // 推送标题
                'content' => $alert, // 推送内容
                'extras' => $extras, // 扩展字段
                'informType' => 0, //通知栏样式 0默认 1大文本 2收件箱 3大图片
                'bigText' => '', // 大文本内容
                'bigPicPath' => '', // 大图片路径
                'timeToLive' => 86400, // 默认86400
                'device_tokens' => $userRegidData['device_token'] ?? '',
            ];

            $res = $this->pushOne($pushData);

            if (!isset($res['message']))
            {
                $res['message'] = '未知错误';
            }

            return $res;
        }
        return ['success' => true];
    }

    /**
     * 向特定设备推送消息
     * @param $regid
     * @param $alert
     * @param $data
     * @return mixed
     */
    public function pushSpecial($regid, $alert, $data)
    {
        // \think\Log::write('进入个推','log',true);

        $client = new JPush($this->app_key, $this->app_secret, null);

        $extras = $this->getExtraData($data);

        $androidParam = [
            'builder_id' => 0,
            'style' => 0,
            'priority' => 1,
            'extras' => $extras,
        ];

        $iosParam = [
//            "builder_id" => 0,
//            "style" => 0,
//            "priority" => 1,
//            "badage" => '+1',
            'sound' => 'default',
            'extras' => $extras,
        ];

        $platform = ['ios', 'android'];

        $options = [
            'apns_production' => true,
        ];

        try
        {
            $result = $client->push()
                ->setPlatform($platform)
                // ->options(['apns_production'=>true])//苹果生产环境
                ->addRegistrationId($regid)
                ->iosNotification($alert, $iosParam)
                ->androidNotification($alert, $androidParam)
                ->options($options)
                ->send();
//            \think\Log::write('推送记录：' . var_export($result, true), 'log', true);
        }
        catch (\Exception $e)
        {
            $result = [];
            Log::write('推送失败：' . $e->getMessage(), 'push_error', true);
        }

        return $this->json_array($result);
    }

    public function getExtraData($data = [])
    {
        switch ($data['action'])
        {
            case 'rectification_details':
                $extras = [
                    'target' => 'local',
                    'link' => $data['action'] . '?id=' . $data['id'] . '&need_auth=1',
                ];
                break;
            case 'fortune_for_month':
//                $extras = [
//                    'target' => 'local',
//                    'link' => $data['action'] . '?rid=' . $data['rid'] . '&time=' . $data['time'],
//                ];
//                break;
            case 'fortune_for_year':
                $extras = [
                    'target' => 'local',
                    'link' => $data['action'] . '?rid=' . $data['rid'] . '&time=' . $data['time'] . '&need_auth=1',
                ];
                break;
            case 'acg_map'://地图首页
            case 'report_index'://报告首页
                $extras = [
                    'target' => 'local',
                    'link' => $data['action'] . '?rid=' . $data['rid'] . '&need_auth=1',
                ];
                break;
            case 'report_details'://报告详情
                $extras = [
                    'target' => 'local',
                    'link' => $data['action'] . '?rid=' . $data['rid'] . '&gid=' . $data['gid'] . '&need_auth=1',
                ];
                break;
            case 'discount_coupon_center':
                $extras = [
                    'target' => 'local',
                    'link' => 'discount_coupon_center?need_auth=2',
                ];
                break;
            case 'refresh_archives':
                $extras = [
                    'target' => 'local',
                    'link' => 'refresh_archives?need_auth=2',
                ];
                break;
            case 'reply_me':
                $extras = [
                    'target' => 'local',
                    'link' => 'reply_me?need_auth=2',
                ];
                break;
            case 'valentine2020':
                $extras = [
                    'target' => 'link',
                    'link' => Env::get('host.domain') . '/web/valentine/index2020?need_auth=1',
                ];
                break;
            case 'valentine2021':
                $extras = [
                    'target' => 'link',
                    'link' => $data['link'],
                ];
                break;
            case 'custom_report_result_info':
                $extras = [
                    'target' => 'local',
                    'link' => "custom_report_result_info?id={$data['pid']}type={$data['type']}&need_auth=1",
                ];
                break;
            case 'synastry_report':
                $extras = [
                    'target' => 'link',
                    'link' => Env::get('host.domain') . "/web/synastry_report/index?id={$data['id']}&zhunle_not_show_nav=1&zhunle_nav_text_color=1&need_auth=1",
                ];
                break;
            case 'extend':
                $extras = [
                    'target' => $data['target'],
                    'link' => $data['link'],
                ];
                break;
            default :
                $extras = [];
                break;
        }
        if (isset($data['pop_msg']))
        {
            $extras['pop_msg'] = $data['pop_msg'];
        }
        return $extras;
    }

    /**
     * 将数据先转换成json,然后转成array
     * @param $result
     * @return mixed
     */
    private function json_array($result)
    {
        $result_json = json_encode($result);
        return json_decode($result_json, true);
    }

    /**
     * 单推推送
     * @param array $data
     *  $data = [
     *      'plantform' => 1, // 1 => all  2 => IOS 3 => android
     *      'pushType' => 1, // 推送方式 huawei=>5 xiaomi=>4 vivo=>3 oppo=>2 极光=> 1
     *      'regid' => [], // 推送用户 array
     *      'title' => '', // 推送标题
     *      'content' => '', // 推送内容
     *      'extras' => '', // 扩展字段
     *      'informType' => 0, //通知栏样式 0默认 1大文本 2收件箱 3大图片
     *      'bigText' => '', // 大文本内容
     *      'bigPicPath' => '', // 大图片路径
     *      'timeToLive' => 86400
     *   ];
     * @return array|mixed
     * @throws GuzzleException
     * @throws \Exception
     */
    public function pushOne($data)
    {
        try
        {
            switch ($data['pushType'])
            {
                case 5: // 华为推送
                    $hwPush = new Huawei($this->config['huawei']);
                    $hwCacheModel = CacheManage::getInstance()->setCacheConfig($this->pushTokenCacheModel, $this->cacheId['huawei']);
                    $token = $hwCacheModel->getCache(); // 缓存
                    if (!$token)
                    {
                        $tokenData = $hwPush->getAccessToken();
                        if ($tokenData['success'])
                        {
                            $token = $tokenData['data']['access_token'];
                            // token 写入缓存
                            $hwCacheModel->setCache($token, 'details', false);
                        } else
                        {
                            return [
                                'success' => false,
                                'message' => '获取推送AccessToken失败',
                            ];
                        }
                    }
                    $res = $hwPush->setData($data)->push($token, $data['regid']);
                    break;
                case 4: // 小米推送
                    $miPush = new Xiaomi($this->config['xiaomi']);
                    $res = $miPush->setData($data)->pushOne($data['regid']);
                    if ($res['result'] === 'ok')
                    {
                        $res['success'] = true;
                    } else
                    {
                        $res['success'] = false;
                    }
                    break;
                case 3: // vivo 推送
                    $vivoPush = new Vivo($this->config['vivo']);
                    $vivoCacheModel = CacheManage::getInstance()->setCacheConfig($this->pushTokenCacheModel, $this->cacheId['vivo']);
                    $token = $vivoCacheModel->getCache(); // 缓存
                    if (!$token)
                    {
                        $tokenData = $vivoPush->getAccessToken();
                        if ($tokenData['success'] && $tokenData['data']['result'] == 0)
                        {
                            $token = $tokenData['data']['authToken'];
                            // token 写入缓存
                            $vivoCacheModel->setCache($token, 'details', false);
                        } else
                        {
                            return [
                                'success' => false,
                                'message' => 'vivo获取推送AccessToken失败',
                            ];
                        }
                    }
                    // Log::write('vivo推送'.var_export($data,true),'error');
                    if (count($data['regid']) > 1)
                    {   // 批量单推
                        $res = $vivoPush->setData($data)->batchPushOne($token, $data['regid']);
                    } else
                    {  //单推
                        $res = $vivoPush->setData($data)->pushOne($token, current($data['regid']));
                    }

                    if (!$res['success'] || $res['data']['result'] != 0)
                    {
                        Log::write('vivo推送失败；错误消息：' . json_encode($res, JSON_UNESCAPED_UNICODE) . ',推送消息：' . json_encode($data, JSON_UNESCAPED_UNICODE), 'error', true);
                        $res = [
                            'success' => false,
                            'message' => json_encode($res, JSON_UNESCAPED_UNICODE),
                        ];
                    }
                    break;
                case 2: // oppo 推送
                    $oppoPush = new Oppo($this->config['oppo']);
                    $oppoCacheModel = CacheManage::getInstance()->setCacheConfig($this->pushTokenCacheModel, $this->cacheId['oppo']);
                    $token = $oppoCacheModel->getCache(); // 缓存
                    if (!$token)
                    {
                        $tokenData = $oppoPush->getAccessToken();
                        if ($tokenData['success'])
                        {
                            $token = $tokenData['data']['data']['auth_token'];
                            // token 写入缓存
                            $oppoCacheModel->setCache($token, 'details', false);
                        } else
                        {
                            return [
                                'success' => false,
                                'message' => '获取推送AccessToken失败',
                            ];
                        }
                    }
                    $res = $oppoPush->setData($data)->batchPushOne($token, $data['regid']);
                    break;
                default:// 极光推送

                    //个推
                    if ($this->config['apns']['is_use'])
                    {
                        if (!isset($data['is_jpush']) || (isset($data['is_jpush']) && (int)$data['is_jpush'] === 0))
                        {
                            if (!isset($data['device_tokens']) && isset($data['regid']))
                            {//如果 device_tokens 为空，并且regid不为空的话，那么进行查询device_tokens
                                if (is_array($data['regid']) && count($data['regid']) === 1)
                                {
                                    $user_push = (new UserPush())->field('device_token,push_type,regid,character_status')->where(['regid' => $data['regid'][0]])->find();
                                    $device_token = $user_push['device_token'] ?? '';
                                } else
                                {
                                    Log::write('个推：regid count > 0，params=' . $data['regid'], 'error', true);
                                }
                            } else
                            {//设置了 device_tokens
                                $device_token = $data['device_tokens'];
                            }

                            if (!empty($device_token))
                            {//apns推送
                                $apnsPush = new ApnsPush($this->config['apns']);
                                $res = $apnsPush->setData($data)->push($device_token);
                                if ((int)$res['http_code'] === 200)
                                {
                                    $res['success'] = true;
                                } else
                                {
                                    $res['success'] = false;
                                }

                                return $res;
                            }
                        }
                    }

                    $jPush = new \XznsTools\push\Jpush($this->config['jpush']);
                    $res = $jPush->setData($data)->push($data['regid']);

                    if ((int)$res['http_code'] === 200)
                    {
                        Log::write('发送极光推送成功：data=' . json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ',res=' . json_encode($res), 'log', true);
                        $res['success'] = true;
                    } else
                    {
                        Log::write('发送极光推送失败：data=' . json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ',res=' . json_encode($res), 'log', true);
                        $res['success'] = false;
                    }
            }

        }
        catch (\Exception $e)
        {
            Log::write('个推失败[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $e->getMessage(), 'error', true);

            return [
                'success' => false,
                'message' => $e->getMessage(),
            ];
        }

        return $res;
    }
}
